home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 284_01 / cpmfile.c < prev    next >
Text File  |  1989-03-11  |  10KB  |  422 lines

  1. /*
  2.  * cpmfile.c - a monolithic program to access vertual CP/M floppy
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <fcntl.h>
  7.  
  8. extern long lseek ();
  9. extern char * memcpy ();
  10. extern char * memset ();
  11.  
  12. #define DISK        "CPMDAT.DSK"
  13.  
  14. #define NOTUSED        0xE5
  15. #define DIRMAX        64
  16. #define MINBLOCK    2
  17. #define MAXBLOCK    243
  18.  
  19. #define BINRD        "rb"
  20. #define ASCRD        "rt"
  21. #define BINWR        "wb"
  22. #define ASCWR        "wt"
  23.  
  24. #define DSKREAD        ( O_RDONLY | O_BINARY )
  25. #define DSKWRIT        ( O_WRONLY | O_BINARY )
  26.  
  27. #define MESSAGE(s,t)    fprintf( stderr, (s), (t) )
  28. #define USGOUT()    fprintf( stderr, usfmt, usage ); return( 1 )
  29. #define ERROUT(s,t)    fprintf( stderr, (s), (t) ); return( 1 )
  30.  
  31. #define TRUE        1
  32. #define FALSE        0
  33.  
  34. char usage [] = "[-webvl][-d disk][-u user][-o file] filename ...";
  35. char usfmt [] = "usage: cpmfile %s\n";
  36.  
  37. char dirbuf [ DIRMAX ][ 32 ];
  38. char recbuf [ 128 ];
  39. char block  [ MAXBLOCK ];
  40.  
  41. main ( argc, argv )
  42.     int argc;
  43.     char * argv [];
  44. {
  45.     int binary, verbos, wrmode, ermode, lister;
  46.     char * disk, * file, * user;
  47.     int uid;
  48.     int argpos;
  49.     FILE * fp;
  50.     int dfd;
  51.     char * dirptr;
  52.     int reel, ext;
  53.     int exist;
  54.     int state;
  55.     int i, n, c;
  56.     char * u, * v, ** p;
  57.     int r;
  58.     char fcb [ 13 ];
  59.  
  60.     /* set options to default */
  61.     binary = verbos = wrmode = ermode = lister = FALSE;
  62.     file = NULL;
  63.     disk = DISK;
  64.     user = "";
  65.  
  66.     /* fetch options and record them */
  67.     argpos = 1;
  68.     while ( argpos < argc && argv[ argpos ][ 0 ] == '-' ) {
  69.     switch ( argv[ argpos ][ 1 ] ) {
  70.     case 'b': binary = TRUE; argpos++; continue;
  71.     case 'v': verbos = TRUE; argpos++; continue;
  72.     case 'w': wrmode = TRUE; argpos++; continue;
  73.     case 'e': ermode = TRUE; argpos++; continue;
  74.     case 'l': lister = TRUE; argpos++; continue;
  75.     case 'd': p = &disk; break;
  76.     case 'o': p = &file; break;
  77.     case 'u': p = &user; break;
  78.     default:
  79.         USGOUT();
  80.     }
  81.     if ( argv[ argpos ][ 2 ] != '\0' ) {
  82.         *p = &argv[ argpos ][ 2 ];
  83.         argpos++;
  84.     } else if ( argpos + 1 < argc ) {
  85.         *p = argv[ argpos + 1 ];
  86.         argpos += 2;
  87.     } else {
  88.         USGOUT();
  89.     }
  90.     }
  91.  
  92.     /* check consistency of options */
  93.     if ( ( wrmode | ermode ) + lister + ( file != NULL ) > 1 ) {
  94.     ERROUT( "-w, -e, -l and -o are excluseve (except -w and -e)\n", NULL );
  95.     }
  96.  
  97.     /* get user id */
  98.     uid = atoi( user );
  99.  
  100.     /* at least one file name must be present */
  101.     if ( argpos >= argc && !lister ) {
  102.     USGOUT();
  103.     }
  104.  
  105.     /* open common output file when -o flag is present */
  106.     if ( file != NULL ) {
  107.     if ( strcmp( file, "-" ) == 0 ) {
  108.         fp = stdout;
  109.     } else {
  110.         fp = fopen( file, binary ? BINWR : ASCWR );
  111.         if ( fp == NULL ) {
  112.         ERROUT( "cannot open %s for output\n", file );
  113.         }
  114.     }
  115.     }
  116.  
  117.     /* open CP/M disk */
  118.     dfd = open( disk, DSKREAD );
  119.     if ( dfd < 0 ) {
  120.     ERROUT( "cannot open disk file %s for input\n", disk );
  121.     }
  122.  
  123.     /* load CP/M directory */
  124.     if ( read( dfd, ( char * )dirbuf, 32 * DIRMAX ) < 32 * DIRMAX ) {
  125.     ERROUT( "disk read error on directory\n", NULL );
  126.     }
  127.  
  128.     /* display file names when listing */
  129.     if ( lister ) {
  130.     for ( i = 0; i < DIRMAX; i++ ) {
  131.         u = dirbuf[ i ];
  132.         if ( ( u[ 0 ] & 0xFF ) != NOTUSED && u[ 0 ] == 0 ) {
  133.         if ( user[ 0 ] != '\0' && ( u[ 0 ] & 0xFF ) != uid ) continue;
  134.         printf( "%2d: %8.8s.%3.3s\n", u[ 0 ] & 0xFF, u + 1, u + 9 );
  135.         }
  136.     }
  137.     return( 0 );
  138.     }
  139.  
  140.     /* change access mode of disk when writing or erasing */
  141.     if ( wrmode || ermode ) {
  142.     close( dfd );
  143.     dfd = open( disk, DSKWRIT );
  144.     if ( dfd < 0 ) {
  145.         ERROUT( "cannot open disk file %s for output\n", disk );
  146.     }
  147.     }
  148.  
  149.     /* build used block table */
  150.     for ( i = 0; i < DIRMAX; i++ ) {
  151.     if ( ( dirbuf[ i ][ 0 ] & 0xFF ) != NOTUSED ) {
  152.         for ( n = 16; n < 32; n++ ) {
  153.         block[ dirbuf[ i ][ n ] & 0xFF ] = TRUE;
  154.         }
  155.     }
  156.     }
  157.  
  158.     /* process each file */
  159.     for ( ; argpos < argc; argpos++ ) {
  160.  
  161.     /* echo file name when -v flag is present */
  162.     if ( verbos ) MESSAGE( "%s\n", argv[ argpos ] );
  163.  
  164.     /* fill CP/M FCB with given name */
  165.     u = argv[ argpos ];
  166.     v = fcb;
  167.     /* set user id */
  168.     *v++ = uid;
  169.     /* set primary name */
  170.     while ( v < fcb + 9 ) {
  171.         if ( *u != '\0' && *u != '.' ) {
  172.         *v++ = toupper( *u++ );
  173.         } else {
  174.         *v++ = ' ';
  175.         }
  176.     }
  177.     /* skip extra characters */
  178.     while ( *u != '\0' && *u != '.' ) u++;
  179.     if ( *u == '.' ) u++;
  180.     /* set extention name */
  181.     while ( v < fcb + 12 ) {
  182.         if ( *u != '\0' ) {
  183.         *v++ = toupper( *u++ );
  184.         } else {
  185.         *v++ = ' ';
  186.         }
  187.     }
  188.  
  189.     /* check existance of the file */
  190.     exist = FALSE;
  191.     for ( i = 0; i < DIRMAX; i++ ) {
  192.         if ( memcmp( dirbuf[ i ], fcb, 12 ) == 0 ) {
  193.         exist = TRUE;
  194.         break;
  195.         }
  196.     }
  197.  
  198.     /* warn exist or non-exist cases */
  199.     if ( exist ) {
  200.         if ( wrmode && !ermode ) {
  201.         MESSAGE( "CP/M file %s exist\n", argv[ argpos ] );
  202.         continue;
  203.         }
  204.     } else {
  205.         if ( !wrmode ) {
  206.         MESSAGE( "CP/M file %s not exist\n", argv[ argpos ] );
  207.         continue;
  208.         }
  209.     }
  210.  
  211.     /* open file if nessesary */
  212.     if ( wrmode ) {
  213.         fp = fopen( argv[ argpos ], binary ? BINRD : ASCRD );
  214.         if ( fp == NULL ) {
  215.         ERROUT( "cannot open %s for input\n", argv[ argpos ] );
  216.         }
  217.     } else if ( file == NULL && !ermode ) {
  218.         fp = fopen( argv[ argpos ], binary ? BINWR : ASCWR );
  219.         if ( fp == NULL ) {
  220.         ERROUT( "cannot open %s for output\n", argv[ argpos ] );
  221.         }
  222.     }
  223.  
  224.     /* erase the file if required */
  225.     if ( ermode ) {
  226.         for ( i = 0; i < DIRMAX; i++ ) {
  227.         if ( memcmp( dirbuf[ i ], fcb, 12 ) == 0 ) {
  228.             dirbuf[ i ][ 0 ] = NOTUSED;
  229.             for ( n = 16; n < 32; n++ ) {
  230.             block[ dirbuf[ i ][ n ] & 0xFF ] = FALSE;
  231.             }
  232.         }
  233.         }
  234.     }
  235.  
  236.     /* read the file if required */
  237.     if ( !wrmode && !ermode ) {
  238.  
  239.         /* read from extent 0 */
  240.         ext = 0;
  241.         for (;;) {
  242.  
  243.         /* search directory entry for ext'th extent */
  244.         fcb[ 12 ] = ext;
  245.         for ( i = 0; i < DIRMAX; i++ ) {
  246.             if ( memcmp( dirbuf[ i ], fcb, 13 ) == 0 ) break;
  247.         }
  248.  
  249.         /* if there's no entry, it means EOF */
  250.         if ( i == DIRMAX ) break;
  251.  
  252.         /* set up parameters of current extent */
  253.         reel = dirbuf[ i ][ 15 ] & 0xFF;
  254.         dirptr = &dirbuf[ i ][ 16 ];
  255.  
  256.         /* read all records in the extent */
  257.         for ( i = 0; i < reel; i++ ) {
  258.  
  259.             /* get current block number */
  260.             r = dirptr[ i / 8 ] & 0xFF;
  261.  
  262.             /* seek to current record position */
  263.             if ( lseek( dfd, r * 1024L + ( i & 7 ) * 128L, 0 ) < 0 ) {
  264.             ERROUT( "disk seek error in %s\n", argv[ argpos ] );
  265.             }
  266.  
  267.             /* read a record */
  268.             if ( read( dfd, recbuf, 128 ) < 128 ) {
  269.             ERROUT( "disk read error in %s\n", argv[ argpos ] );
  270.             }
  271.  
  272.             /* write a record, converting if needed */
  273.             for ( u = recbuf; u < recbuf + 128; u++ ) {
  274.             if ( binary ) {
  275.                 putc( *u, fp );
  276.             } else {
  277.                 switch ( *u ) {
  278.                 case 0x0A: putc( '\n', fp ); break;
  279.                 case 0x0D: break;
  280.                 case 0x1A: goto ReadEOF;
  281.                 default:   putc( *u, fp ); break;
  282.                 }
  283.             }
  284.             }
  285.  
  286.         }
  287.  
  288.         /* if this extent is last one, end reading */
  289.         if ( reel < 128 ) break;
  290.  
  291.         /* succeed extent number */
  292.         ext++;
  293.         }
  294.  
  295.     ReadEOF:;
  296.     }
  297.  
  298.     /* write file if required */
  299.     if ( wrmode ) {
  300.  
  301.         /* write from extent 0, state 0 */
  302.         ext = 0;
  303.         state = 0;
  304.         for (;;) {
  305.  
  306.         /* get free directory entry */
  307.         for ( i = 0; i < DIRMAX; i++ ) {
  308.             if ( ( dirbuf[ i ][ 0 ] & 0xFF ) == NOTUSED ) break;
  309.         }
  310.         if ( i == DIRMAX ) {
  311.             ERROUT( "directory full on %s\n", argv[ argpos ] );
  312.         }
  313.  
  314.         /* fill the directory entry */
  315.         memset( dirbuf[ i ], 0x00, 32 );
  316.         memcpy( dirbuf[ i ], fcb, 12 );
  317.         dirbuf[ i ][ 12 ] = ext;
  318.  
  319.         /* set block list pointer */
  320.         dirptr = &dirbuf[ i ][ 16 ];
  321.  
  322.         /* fill blocks in the extent */
  323.         for ( i = 0; i < 128; i++ ) {
  324.  
  325.             /* stop looping if input is exhousted */
  326.             if ( state == 2 ) break;
  327.             if ( binary ) {
  328.             c = getc( fp );
  329.             if ( c == EOF ) break;
  330.             ungetc( c, fp );
  331.             }
  332.  
  333.             /* read 128 bytes data from the file */
  334.             for ( u = recbuf; u < recbuf + 128; u++ ) {
  335.             switch ( state ) {
  336.             case 0:
  337.                 c = getc( fp );
  338.                 if ( c == EOF ) {